﻿using Microsoft.Win32;
using System.Collections.Concurrent;
using System.IO;
using System.Windows.Input;

namespace EnvCheck.Utils;

public interface IAsyncInstalledAppReceiver
{
    void Receive(string name, string version);
}
public interface IProgressReceiver
{
    void ReportProgress(int current, int total);
}


/// <summary>
/// 服务类，用于获取已安装的应用程序列表
/// </summary>
/// 

public static class InstalledAppService
{

    private static readonly Dictionary<string, string> Registries = [];
    public static void Reload(IAsyncInstalledAppReceiver receiver = null, IProgressReceiver? progressCallback = null)
    {
        Registries.Clear();
        AsyncLoadInstalledApps(receiver, progressCallback);
    }
    /// <summary>
    /// 异步获取已安装的应用程序列表
    /// </summary>
    /// <param name="receiver">
    /// 接收已安装应用程序的接口
    /// </param>
    public static void AsyncLoadInstalledApps(IAsyncInstalledAppReceiver receiver=null, IProgressReceiver? progressCallback = null)
    {
        var installedApps = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        List<string> keyList =
        [
            @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
            @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
        ];
        int total = 0, progress = 0;

        var mainKeysReadQueue = new ConcurrentQueue<string>();
        if (Registries.Keys.Count != 0)
        {
            foreach (var key in Registries.Keys)
            {
                if (Registries.TryGetValue(key, out var value))
                {
                    progressCallback?.ReportProgress(total, ++progress);
                    receiver?.Receive(key, value);
                }
            }
            return;
        }
        foreach (var keyPath in keyList)
        {
            using var key = Registry.LocalMachine.OpenSubKey(keyPath);
            if (key == null)
            {
                return;
            }
            var subNames = key.GetSubKeyNames();
            total += subNames.Length;
            foreach (var subname in subNames)
            {
                mainKeysReadQueue.Enqueue(Path.Combine(keyPath, subname));
            }
        }
        
        //progressCallback?.Invoke(total, sum);
        while (!mainKeysReadQueue.IsEmpty)
        {
            progressCallback?.ReportProgress(total, ++progress);
            if (!mainKeysReadQueue.TryDequeue(out string subName))
                continue;

            using var subkey = Registry.LocalMachine.OpenSubKey(subName);

            var version = subkey?.GetValue("DisplayVersion") as string;
            var name = subkey?.GetValue("DisplayName") as string;
            if (name == null || name.Length == 0)
            {
                continue;
            }
            if (version != null)
                VersionCompareHelper.RegularizeAppName(ref name, version);

            Serilog.Log.Debug($"Found installed app: \tName\t\t{name}\tVersion\t\t{version}");
            Registries[name] = version ?? "Unknown";
            receiver?.Receive(name, Registries[name]);
        }
    }
}
